#pragma once

#include "znx_http_conf.h"
#include "comm/znx_hash_tab.h"

#define ZNX_HTTP_PERFIX_MATCH_PATH      1
#define ZNX_HTTP_EXACT_MATCH_PATH       2
#define ZNX_HTTP_REGEX_MATCH_PATH       3

typedef struct znx_http_site_conf_s         znx_http_site_conf_t;
typedef struct znx_http_addr_site_conf_s    znx_http_addr_site_conf_t;
typedef struct znx_http_loc_conf_s          znx_http_loc_conf_t;


struct znx_http_loc_conf_s {
    int64_t                     type;
    znx_str_t                   path;
    void                        **l_modules;
    znx_http_addr_site_conf_t   *addr_site;
};


struct znx_http_addr_site_conf_s {
    // element is znx_string.
    znx_array_t                 *address_names;
    // element is znx_address.
    znx_array_t                 *address_arr;
    znx_http_core_conf_t        *server_core_conf;
    znx_http_core_conf_t        *proxy_core_conf;

    void                        **a_modules;
    // element is znx_http_loc_conf_t.
    znx_array_t                 *loc_confs;
    znx_http_site_conf_t        *site_conf;
};


struct znx_http_site_conf_s {
    znx_atomic_int64_t          refer;
    znx_hash_node_t             hash_node;
    int64_t                     version;

    znx_str_t                   server_name;
    znx_http_core_conf_t        *server_core_conf;
    znx_http_core_conf_t        *proxy_core_conf;

    void                        **s_modules;
    // elements is znx_http_addr_site.
    znx_array_t                 *addr_sites;
    znx_pool_t                  *pool;
    znx_str_t                   err;
};


static inline znx_http_site_conf_t *
znx_http_site_conf_create()
{
    znx_pool_t                      *pool;
    znx_http_site_conf_t            *site_conf;

    pool = znx_pool_create_ext(ZNX_POOL_MIN_PAGE_SIZE);
    site_conf = znx_pool_calloc(pool, sizeof(znx_http_site_conf_t));
    site_conf->refer = 1;
    // site_conf->version = 0;
    site_conf->pool = pool;
    site_conf->s_modules = znx_pool_calloc(pool,
        sizeof(void *) * (size_t)http_modules_num);
    return site_conf;
}


static inline void
znx_http_site_conf_hold(znx_http_site_conf_t *site_conf)
{
    znx_atomic_int64_add_fetch(&site_conf->refer, 1);
}


static inline void
znx_http_site_conf_free(znx_http_site_conf_t *site_conf)
{
    int64_t         new_refer;
    new_refer = znx_atomic_int64_add_fetch(&site_conf->refer, -1);

    if (new_refer < 0) {
        ZNX_DEF_LOG_FATAL(NULL, "new_refer must be greater than or equal to 0");
    }

    if (new_refer > 0) {
        return;
    }

    znx_pool_destroy(site_conf->pool);
}


static inline void
znx_http_site_conf_free_handle(void *data)
{
    znx_http_site_conf_free((znx_http_site_conf_t *)data);
}


znx_bool_t
znx_http_site_conf_parse(znx_http_site_conf_t *site_conf,
    const char *filepath, znx_str_t *server_name);


#define znx_http_get_site_module_conf(site_conf, module)                    \
    site_conf->s_modules[module.index]

#define znx_http_set_site_module_conf(site_conf, module, module_conf)       \
    site_conf->s_modules[module.index] = module_conf

#define znx_http_get_addr_site_module_conf(addr_site, module)               \
    addr_site->a_modules[module.index]

#define znx_http_set_addr_site_module_conf(addr_site, module, module_conf)  \
    addr_site->a_modules[module.index] = module_conf

#define znx_http_get_loc_module_conf(loc_conf, module)                     \
    loc_conf->l_modules[module.index]

#define znx_http_set_loc_module_conf(loc_conf, module, module_conf)        \
    loc_conf->l_modules[module.index] = module_conf